<template>
	<div class="file-uploader">
		<el-upload
			class="upload-area"
			drag
			action="#"
			:auto-upload="false"
			:show-file-list="true"
			:limit="1"
			:on-change="handleFileChange"
			:on-exceed="handleExceed"
			:on-remove="handleRemove"
			:file-list="fileList"
			accept=".xlsx,.xls"
		>
			<el-icon class="el-icon--upload"><upload-filled /></el-icon>
			<div class="el-upload__text">拖拽Excel文件到此处或 <em>点击上传</em></div>
			<template #tip>
				<div class="el-upload__tip">请上传Excel格式文件(.xlsx或.xls)，文件大小不超过10MB</div>
			</template>
		</el-upload>

		<div class="action-buttons" v-if="fileList.length > 0">
			<el-button type="primary" @click="parseExcelFile">解析文件</el-button>
			<el-button @click="resetUpload">重置</el-button>
		</div>
	</div>
</template>

<script lang="ts" setup>
import { ref, defineEmits } from 'vue'
import { ElMessage, UploadFile, UploadUserFile } from 'element-plus'
import { UploadFilled } from '@element-plus/icons-vue'
import * as XLSX from 'xlsx'

const emit = defineEmits(['file-selected', 'file-parsed'])

// 文件列表
const fileList = ref<UploadUserFile[]>([])

// 处理文件变更
const handleFileChange = (uploadFile: UploadFile) => {
	fileList.value = [uploadFile]
	emit('file-selected')
}

// 处理超出文件限制
const handleExceed = () => {
	ElMessage.warning('只能上传一个Excel文件')
}

// 处理移除文件
const handleRemove = () => {
	fileList.value = []
}

// 重置上传
const resetUpload = () => {
	fileList.value = []
}

// 解析Excel文件
const parseExcelFile = async () => {
	if (fileList.value.length === 0) {
		ElMessage.warning('请先选择Excel文件')
		return
	}

	const file = fileList.value[0].raw
	if (!file) {
		ElMessage.error('文件不存在')
		return
	}

	// 检查文件大小 (10MB)
	const maxSize = 10 * 1024 * 1024
	if (file.size > maxSize) {
		ElMessage.error('文件大小不能超过10MB')
		return
	}

	try {
		const data = await readExcelFile(file)
		if (data.length === 0) {
			ElMessage.warning('Excel文件中没有数据')
			return
		}

		// 获取表头（第一行）
		const headers = Object.keys(data[0])
		emit('file-parsed', data, headers)
		ElMessage.success('文件解析成功')
	} catch (error) {
		console.error('解析Excel文件出错:', error)
		ElMessage.error('解析Excel文件出错')
	}
}

// 读取Excel文件内容
const readExcelFile = (file: File): Promise<any[]> => {
	return new Promise((resolve, reject) => {
		const reader = new FileReader()

		reader.onload = (e) => {
			try {
				console.log('=== Excel文件解析开始 ===')
				const data = e.target?.result
				const workbook = XLSX.read(new Uint8Array(data as ArrayBuffer), { type: 'array' })
				console.log('工作簿信息：', workbook.SheetNames)

				const firstSheetName = workbook.SheetNames[0]
				const worksheet = workbook.Sheets[firstSheetName]

				/**
				 * 获取原始数据，不指定表头，按原样获取全部内容
				 * 设置header为1表示按数组返回，defval为空字符串表示空单元格默认值
				 */
				const rawData = XLSX.utils.sheet_to_json<any[]>(worksheet, { header: 1, defval: '' })

				console.log('原始数据行数：', rawData.length)

				// 解析Excel表头和数据
				const { headers, jsonData } = parseExcelContent(rawData)

				console.log('=== 解析结果 ===')
				console.log('解析后的表头：', headers)
				console.log('有效数据行数：', jsonData.length)

				// 将解析结果传递给父组件
				emit('file-parsed', jsonData, headers)
				resolve(jsonData)
			} catch (error) {
				console.error('Excel解析错误：', error)
				reject(error)
			}
		}

		reader.onerror = (error) => {
			reject(error)
		}

		reader.readAsArrayBuffer(file)
	})
}

/**
 * 解析Excel内容，提取表头和数据
 * @param rawData Excel原始数据数组
 * @returns 提取的表头和数据
 */
const parseExcelContent = (
	rawData: any[]
): { headers: string[]; jsonData: Record<string, any>[] } => {
	// 查找真正的表头和数据起始行
	const { headerRows, dataStartRow } = findHeaderAndDataRows(rawData)
	console.log('表头行索引：', headerRows, '数据起始行：', dataStartRow)

	// 构建复合表头
	const headers = buildComplexHeaders(rawData, headerRows)

	// 提取有效数据行
	const jsonData = extractValidDataRows(rawData, headers, dataStartRow)

	return { headers, jsonData }
}

/**
 * 查找表头和数据起始行
 * @param rawData Excel原始数据数组
 * @returns 表头行索引数组和数据起始行索引
 */
const findHeaderAndDataRows = (rawData: any[]): { headerRows: number[]; dataStartRow: number } => {
	let headerRows: number[] = [] // 保存表头行的索引
	let dataStartRow = 0 // 数据起始行

	// 查找表头行和数据起始行
	for (let i = 0; i < rawData.length; i++) {
		const row = rawData[i] as any[]

		// 查找包含"序号"或"学号"的行作为表头行
		const hasSequence = row.some((cell: any) => {
			const cellStr = String(cell).replace(/\r?\n/g, '') // 移除换行符
			return cellStr.includes('序号') || cellStr.includes('序 号')
		})
		const hasStudentId = row.some((cell: any) => String(cell).includes('学号'))

		if (hasSequence || hasStudentId) {
			console.log(`找到主表头行：第${i}行`)
			headerRows.push(i)

			// 检查下一行是否是子表头行（包含"理论"、"实践"）
			if (i + 1 < rawData.length) {
				const nextRow = rawData[i + 1] as any[]
				const hasTheoryOrPractice = nextRow.some(
					(cell: any) => String(cell).includes('理论') || String(cell).includes('实践')
				)

				if (hasTheoryOrPractice) {
					console.log(`找到子表头行：第${i + 1}行`)
					headerRows.push(i + 1)
					dataStartRow = i + 2 // 数据从子表头的下一行开始
				} else {
					dataStartRow = i + 1 // 数据从主表头的下一行开始
				}
			} else {
				dataStartRow = i + 1
			}

			break
		}
	}

	// 如果未找到表头，则默认使用第一行作为表头
	if (headerRows.length === 0) {
		console.log('未找到表头，使用第一行作为表头')
		headerRows = [0]
		dataStartRow = 1
	}

	return { headerRows, dataStartRow }
}

/**
 * 构建复合表头，处理多层表头结构
 * @param rawData Excel原始数据数组
 * @param headerRows 表头行索引数组
 * @returns 处理后的表头数组
 */
const buildComplexHeaders = (rawData: any[], headerRows: number[]): string[] => {
	const headers: string[] = []
	const firstHeaderRow = rawData[headerRows[0]] as any[]
	const secondHeaderRow = headerRows.length > 1 ? (rawData[headerRows[1]] as any[]) : null

	for (let i = 0; i < firstHeaderRow.length; i++) {
		// 获取当前单元格内容
		let header = String(firstHeaderRow[i] || '').trim()
		if (header === '') header = `列${i + 1}`

		// 构建表头名称
		let finalHeader = header

		// 如果存在第二行表头，处理复合表头
		if (secondHeaderRow) {
			const subHeader = String(secondHeaderRow[i] || '').trim()

			// 当子表头为理论或实践时，将其与对应的课程名关联
			if (subHeader === '理论' || subHeader === '实践') {
				// 当前列有课程名
				if (header && header !== `列${i + 1}`) {
					finalHeader = `${header}-${subHeader}`
				}
				// 当前列没有课程名，需要向左查找最近的课程名
				else {
					// 向左查找最近的课程名
					for (let j = i - 1; j >= 0; j--) {
						const prevHeader = String(firstHeaderRow[j] || '').trim()
						// 找到非空的课程名
						if (
							prevHeader &&
							prevHeader !== `列${j + 1}` &&
							prevHeader !== '理论' &&
							prevHeader !== '实践'
						) {
							finalHeader = `${prevHeader}-${subHeader}`
							break
						}
					}
				}
			} else if (subHeader && subHeader !== header) {
				// 其他情况下，如果子表头不为空且与主表头不同，则合并
				finalHeader = `${finalHeader}_${subHeader}`
			}
		}

		// 对于姓名列特殊处理
		if (i === 1 && !finalHeader.includes('姓名') && !finalHeader.includes('名字')) {
			if (finalHeader === `列${i + 1}` || finalHeader === '') {
				finalHeader = '姓名'
			}
		}

		headers.push(finalHeader)
	}

	// console.log('构建的复合表头： ', headers)
	return headers
}

/**
 * 提取有效数据行，过滤无效行
 * @param rawData Excel原始数据数组
 * @param headers 处理后的表头数组
 * @param dataStartRow 数据起始行索引
 * @returns 有效数据行数组
 */
const extractValidDataRows = (
	rawData: any[],
	headers: string[],
	dataStartRow: number
): Record<string, any>[] => {
	console.log(`开始提取数据：从第${dataStartRow}行，总共${rawData.length}行`)

	const jsonData: Record<string, any>[] = []

	for (let i = dataStartRow; i < rawData.length; i++) {
		const row = rawData[i] as any[]

		// 跳过空行
		const isEmpty = row.every((cell: any) => !cell || String(cell).trim() === '')
		if (isEmpty) {
			continue
		}

		// 检查是否是签名行或表格尾部
		const firstCell = String(row[0] || '').trim()
		const isSignature = isSignatureOrFooterRow(firstCell, row)

		if (isSignature) {
			console.log(`第${i}行是签名行，跳过：'${firstCell}'`)
			continue
		}

		// 构建数据行对象
		const rowData: Record<string, any> = {}
		for (let j = 0; j < headers.length; j++) {
			rowData[headers[j]] = row[j] || ''
		}
		jsonData.push(rowData)
	}

	console.log(`成功提取${jsonData.length}行有效数据`)
	return jsonData
}

/**
 * 检查是否是签名行或表格尾部
 * @param firstCell 行的第一个单元格内容
 * @param row 行数据
 * @returns 是否是签名行或表格尾部
 */
const isSignatureOrFooterRow = (firstCell: string, row: any[]): boolean => {
	// 检查是否包含年月日（各种格式）
	const hasDateFormat = (text: string): boolean => {
		text = String(text || '')
		return (
			(text.includes('年') && text.includes('月') && text.includes('日')) ||
			(text.includes('年') && text.includes('月'))
		)
	}

	// 检查整行是否有年月日格式
	const rowHasDateFormat = row.some((cell: any) => hasDateFormat(String(cell || '')))

	return (
		firstCell.includes('统计人') ||
		firstCell.includes('签字') ||
		firstCell.includes('审核') ||
		hasDateFormat(firstCell) ||
		rowHasDateFormat ||
		row.filter((cell: any) => cell && String(cell).trim() !== '').length <= 2
	)
}
</script>

<style lang="scss" scoped>
.file-uploader {
	width: 100%;

	.upload-area {
		width: 100%;

		:deep(.el-upload) {
			width: 100%;
		}

		:deep(.el-upload-dragger) {
			width: 100%;
			padding: 30px;
		}

		.el-icon--upload {
			font-size: 48px;
			color: var(--el-color-primary);
			margin-bottom: 10px;
		}

		.el-upload__text {
			color: var(--el-text-color-regular);
			font-size: 16px;

			em {
				color: var(--el-color-primary);
				font-style: normal;
			}
		}

		.el-upload__tip {
			margin-top: 10px;
			color: var(--el-text-color-secondary);
		}
	}

	.action-buttons {
		display: flex;
		justify-content: center;
		gap: 15px;
		margin-top: 20px;
	}
}
</style>
